﻿//================================================
//
//                       _oo0oo_
//                      o8888888o
//                      88" . "88
//                      (| -_- |)
//                      0\  =  /0
//                    ___/`---'\___
//                  .' \\|     |// '.
//                 / \\|||  :  |||// \
//                / _||||| -:- |||||- \
//               |   | \\\  -  /// |   |
//               | \_|  ''\---/''  |_/ |
//               \  .-\__  '-'  ___/-. /
//             ___'. .'  /--.--\  `. .'___
//          ."" '<  `.___\_<|>_/___.' >' "".
//         | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//         \  \ `_.   \_ __\ /__ _/   .-` /  /
//     =====`-.____`.___ \_____/___.-`___.-'=====
//                       `=---='
//
//
//     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//               佛祖保佑         永无BUG
//
//
//
//================================================
//
// Created by Huiyi on 2022/02/18
//
//@模块名称 易炫彩WO套件ORM扩展
//@版本   1.1
//@日期   2023-02-18
//@作者   Huiyi
//@依赖   module_WebOat.h
//@模块备注 易炫彩WO套件的ORM扩展
// 链式生成SQL代码,自动化连接池
// 文档:http://dwiki.hyiy.top/@weboat

#pragma once

#ifndef XL_XEXPAND_DWEBX_ORM_H
//@隐藏{
#define XL_XEXPAND_DWEBX_ORM_H
#include "pool/connect_pool.hpp"
//#include "SQLBuilder.hpp"
#include "SQLStatement.hpp"
#ifdef XC_MODUL
#include "module_base.h"

#endif //  XC_MODUL
#ifdef _WIN64
#ifndef WOPTR
#define WOPTR int64_t
#endif // !WOPTR
#else
#ifndef WOPTR
#define WOPTR int32_t
#endif // !WOPTR
#endif
#include "module_WebOat.h"
//@隐藏}

#ifdef  _WIN64
	//@lib "lib\x64\libmysql.lib"
	//@复制文件 @当前模块路径 "lib\x64\libmysql.dll"
#else
	//@lib "lib\x86\libmysql.lib"
	//@复制文件 @当前模块路径 "lib\x64\libmysql.dll"
#endif

//@src "WebOatOrm.cpp"
//@src "pool/connect.cpp"
//@src "pool/connect_pool.cpp"

//@备注 初始化ORM,未初始化会出现错误
//@参数 主机 数据库主机地址
//@参数 端口 数据库端口
//@参数 用户名 数据库用户名
//@参数 密码 数据库连接密码
//@参数 数据库名 数据库名称
//@参数 初始连接数 连接池初始连接数量
//@参数 最大连接数 连接的最大连接数量
//@参数 空闲超时 连接池的最大空闲时间(s)
//@参数 连接超时 连接池获取连接的超时时间(ms)
//@别名 WoOrm初始化(主机,端口,用户名,密码,数据库名,初始连接数,最大连接数,空闲超时,连接超时)
bool WoSqlOrmInit(
    CXTextA ip,
    unsigned short port,
    CXTextA user,
    CXTextA password,
    CXTextA dbname,
    int init_size = 50,
    int max_size = 2048,
    int max_freeTime = 60,
    int connection_timeout = 300
);

class WoSqlOrm
{
public:
	WoSqlOrm();
	~WoSqlOrm();

    //@备注 直接使用原生SQL,当使用本命令之后所有ORM链都会失效,直到查询结束
    //@别名 置Sql语句(sql语句)
    WoSqlOrm& SetSqlStr(const CXTextA& sql);
    /*@声明
    //@备注 多少条字段都只会扫描第一行,且结构体不能为动态数组
    //@别名 取第一条(接收结构体)
    bool First(通用型& model);
    */
    //@隐藏{
    template<typename T>
    bool First(T& model) {
        //检查反射模型
        auto info = WoRefTypeNameGetHandle(typeid(model).name());
        if (info == nullptr) {
            throw std::exception("WoSqlOrm->First: 模型未注册！");
            return false;
        }
        if (!info->isNesting) {
            throw std::exception("WoSqlOrm->First: 错误的反射模型");
            return false;
        }
        //开始sql事务
        CXTextA s = m_noOrm ? m_rowSqlStr : m_sql.sql();
        m_noOrm = false;
        if (mysql_real_query(*m_connect, s.get(), s.size()) != NULL) {
            m_lastError = "WoSqlOrm->First: ";
            throw std::exception(m_lastError+ mysql_error(*m_connect));
            return false;
        }
        auto result = mysql_store_result(*m_connect);
        if (!result) {
            m_lastError = "WoSqlOrm->First: ";
            throw std::exception(m_lastError + mysql_error(*m_connect));
            return false;
        }
        auto row = mysql_fetch_row(result);
        if (!row) {
            mysql_free_result(result);
            return true;
        }
        MYSQL_FIELD* field;
        std::map<std::string, int> indexs;
        {
            int i = 0;
            while (field = mysql_fetch_field(result)) {
                indexs[field->name] = i;
                i++;
            }
        }
        for (auto iters = info->memberMap.begin(); iters != info->memberMap.end(); iters++) {
            auto find = indexs.find(iters->first.c_str());
            if (find == indexs.end()) {
                continue;
            }
            auto objPtr = WoRefTypeNameGetHandle(iters->second->typeName.c_str());
            if (objPtr == nullptr) {
                continue;
            }
            if (objPtr->refFunc == nullptr) {
                continue;
            }
            //auto r = WoCodingUTF82GBK(row[find->second]);
            objPtr->refFunc(
                (void*)(
                    ((WOPTR)&model)+ iters->second->deviation
                ), row[find->second]//WoCodingUTF8ToGBK(row[find->second])
            );
        }
        mysql_free_result(result);
        return true;
    };
    //@隐藏}
    /*@声明
    //@备注 自动将查找到的数据写入到
    //@别名 查找(接收结构体)
    bool Find(通用型& model);
    */
    //@隐藏{
    template<typename T>
    bool Find(T& model) {
        auto refInfo = WoRefTypeNameGetHandle(typeid(model).name());
        //防止空指针
        if (refInfo == nullptr) {
            m_lastError = "WoSqlOrm->Find: ";
            throw std::exception(m_lastError + "错误的反射模型");
            return false;
        }
        CXTextA arrName;
        WoRefArrarType arrType;
        if (!WoRefModelIfisList(typeid(model).name(), &arrName, &arrType)) {
            return First(model);
        }
        //数组事件
        WoRefModelHandle objPtr  = WoRefTypeNameGetHandle(arrName);
        //防止空
        if (objPtr == nullptr) {
            m_lastError = "WoSqlOrm->Find: ";
            throw std::exception(m_lastError + "错误的子模型");
            return false;
        }

        //开始sql事务
        CXTextA s = m_noOrm ?m_rowSqlStr: m_sql.sql();
        m_noOrm = false;
        if (mysql_real_query(*m_connect, s.get(), s.size()) != NULL) {
            m_lastError = "WoSqlOrm->Find: ";
            throw std::exception(m_lastError + mysql_error(*m_connect));
            return false;
        }
        auto result = mysql_store_result(*m_connect);
        if (!result) {
            m_lastError = "WoSqlOrm->Find: ";
            throw std::exception(m_lastError + mysql_error(*m_connect));
            return false;
        }
        inja::json json;
        MYSQL_FIELD* field;
        std::vector<std::string> fields;
        //字段表
        while (field = mysql_fetch_field(result)) {
            fields.push_back(field->name);
        }

        MYSQL_ROW row;
        while (row = mysql_fetch_row(result)) {
            inja::json obj;
            for ( int i = 0; i < fields.size(); i++)
            {
                obj[fields[i]]= row[i];
            }
            json.push_back(obj);
        }
        auto dStr = json.dump();

        refInfo->refFunc((void*)(&model), dStr.c_str());

        mysql_free_result(result);

        return true;
    }
    //@隐藏}
private:
    std::shared_ptr<Connect> m_connect;
    SQLStatement m_sql;
    CXTextA m_lastError;
    CXTextA m_rowSqlStr;//原生sql
    bool m_noOrm = false;//使用原生sql
public:
    //@别名 更新(表名)
    WoSqlOrm& UPDATE(const CXTextA& table) {
        m_sql.statementType = SQLStatement::StatementType::UPDATE;
        m_sql.tables.emplace_back(table);
        return *this;
    }
    //@别名 更新值(值列表)
    WoSqlOrm& SET(const CXTextA& sets) {
        m_sql.sets.emplace_back(sets);
        return *this;
    }
    //@别名 插入(表名)
    WoSqlOrm& INSERT_INTO(const CXTextA& tableName) {
        m_sql.statementType = SQLStatement::StatementType::INSERT;
        m_sql.tables.emplace_back(tableName);
        return *this;
    }
    //@备注 批量设置数据列与数据值,通常用于插入(insert)
    //@参数 列名列表 例如: "id,name"
    //@参数 值列表 例如: "1,'huiyi'"
    //@别名 置数据对(列名列表,值列表)
    WoSqlOrm& VALUES(const CXTextA& columns, const CXTextA& values) {
        INTO_COLUMNS(columns);
        INTO_VALUES(values);
        return *this;
    }
    //@备注 设置into的列名列表
    //@参数 列名列表 例如: "id,name"
    //@别名 置数据列(列名列表)
    WoSqlOrm& INTO_COLUMNS(const CXTextA& columns) {
        m_sql.columns.emplace_back(columns);
        return *this;
    }
    //@备注 设置into的值列表
    //@参数 置值列表 例如: "1,'huiyi'"
    //@别名 置值列(列名列表)
    WoSqlOrm& INTO_VALUES(const CXTextA& values) {
        m_sql.valuesList.back().emplace_back(values);
        return *this;
    }
    //@别名 置查询段(查询字段)
    WoSqlOrm& SELECT(const CXTextA& columns) {
        m_sql.statementType = SQLStatement::StatementType::SELECT;
        m_sql.select.emplace_back(columns);
        return *this;
    }

    WoSqlOrm& SELECT_DISTINCT(const CXTextA& columns) {
        m_sql.distinct = true;
        return SELECT(columns);
    }

    WoSqlOrm& DELETE_FROM(const CXTextA& table) {
        m_sql.statementType = SQLStatement::StatementType::DELETE_;
        m_sql.tables.emplace_back(table);
        return *this;
    }
    //@别名 置表名(表名)
    WoSqlOrm& FROM(const CXTextA& table) {
        m_sql.tables.emplace_back(table);
        return *this;
    }

    WoSqlOrm& JOIN(const CXTextA& join) {
        m_sql.join.emplace_back(join);
        return *this;
    }

    WoSqlOrm& INNER_JOIN(const CXTextA& join) {
        m_sql.innerJoin.emplace_back(join);
        return *this;
    }

    WoSqlOrm& LEFT_OUTER_JOIN(const CXTextA& join) {
        m_sql.leftOuterJoin.emplace_back(join);
        return *this;
    }

    WoSqlOrm& RIGHT_OUTER_JOIN(const CXTextA& join) {
        m_sql.rightOuterJoin.emplace_back(join);
        return *this;
    }

    WoSqlOrm& OUTER_JOIN(const CXTextA& join) {
        m_sql.outerJoin.emplace_back(join);
        return *this;
    }
    //@别名 置条件(条件)
    WoSqlOrm& WHERE(const CXTextA& conditions) {
        m_sql.where.emplace_back(conditions);
        m_sql.lastList = &m_sql.where;
        return *this;
    }

    WoSqlOrm& OR() {
        m_sql.lastList->emplace_back(m_sql.OR);
        return *this;
    }

    WoSqlOrm& AND() {
        m_sql.lastList->emplace_back(m_sql.AND);
        return *this;
    }

    WoSqlOrm& GROUP_BY(const CXTextA& columns) {
        m_sql.groupBy.emplace_back(columns);
        return *this;
    }

    WoSqlOrm& HAVING(const CXTextA& conditions) {
        m_sql.having.emplace_back(conditions);
        m_sql.lastList = &m_sql.having;
        return *this;
    }

    WoSqlOrm& ORDER_BY(const CXTextA& columns) {
        m_sql.orderBy.emplace_back(columns);
        return *this;
    }

    WoSqlOrm& LIMIT(const CXTextA& variable, const CXTextA& offset) {
        m_sql.limit = variable;
        m_sql.offset = offset;
        return *this;
    }

    WoSqlOrm& LIMIT(const CXTextA& variable) {
        m_sql.limit = variable;
        m_sql.offset = m_sql.offset=="0"?"0": m_sql.offset;
        return *this;
    }

    /**
     * 批量插入时,多插入一行
     * @return
     */
    WoSqlOrm& ADD_ROW() {
        m_sql.valuesList.resize(m_sql.valuesList.size() + 1);
        return *this;
    }

    std::string toString() {
        return m_sql.sql();
    }
};


#endif